package com.example.tangjiangxu.photowallfallsdemo;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.Toast;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 自定义的ScrollView，实现瀑布流
 */
public class MyScrollView extends ScrollView implements View.OnTouchListener {
    private static final String TAG = "MyScrollView";
    /**
     * 每页要加载图片的数量
     */
    private static final int PAGE_SIZE = 15;
    /** 当前页数 **/
    private int page;
    /** 每一列的宽度 **/
    private int columnWidth;
    /** 当前第一列的高度 **/
    private int firstColumnHeight;
    /** 当前第二列的高度 **/
    private int secondColumnHeight;
    /** 当前第三列的高度 **/
    private int thirdColumnHeight;
    /** 是否已加载过一次layout,这里onLayout中的初始化只需要加载一次 **/
    private boolean loadOnce;
    /** 对图片进行管理对工具类 **/
    private ImageLoader imageLoader;
    /** 第一列对布局 **/
    private LinearLayout llfirst;
    /**第二列布局 **/
    private LinearLayout llSecond;
    /** 第三列布局 **/
    private LinearLayout llThird;
    /** SV下的直接子布局 **/
    private static View scrollLayout;
    /** sv布局的高度 **/
    private static int scrollViewHeight;
    /** 记录上一次垂直方向的滚动距离 **/
    private static int lastScrollY = -1;
    /** 记录界面上所有的图片，用以可以随时控制对图片的释放 **/
    private List<ImageView> imageViewList = new ArrayList<ImageView>();
    /** 加载图片的任务，方便返回时取消 **/
    private static Set<LoadImageTask> taskCollection;
    /** 在Handler中进行图片可性检查的判断，以及加载更多图片的操作 **/
    private static Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            MyScrollView myScrollView = (MyScrollView) msg.obj;
            int scrollY = myScrollView.getScrollY();
            //如果当前到滚动位置和上次相同，表示已停止滚动
            if (scrollY == lastScrollY) {
                //当滚动到最底部，并且当前没有正在下载到任务时，开始下载下一页到图片
                //滚动到底部，判断逻辑：sv的高度，加上sv滚动的距离大于等于自控件对高度时，即到底了
                if (scrollViewHeight + scrollY >= scrollLayout.getHeight()
                        && taskCollection.isEmpty()) {
                    myScrollView.loadMoreImage();
                }
                myScrollView.checkVisibility();
            } else {
                lastScrollY = scrollY;
                Message message = Message.obtain();
                message.obj = myScrollView;
                //5毫秒后再次对滚动位置进行判断
                handler.sendMessageDelayed(message,5);
            }
        }
    };

    public MyScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        imageLoader = ImageLoader.getInstance();
        taskCollection = new HashSet<LoadImageTask>();
        setOnTouchListener(this);
    }

    /**
     * 遍历imageViewList的每张图片，对图片对可见性进行价差，如果图片已经离开屏幕可见范围，则将图片替换成一张空图
     */
    private void checkVisibility() {
        for (int i = 0; i < imageViewList.size(); i++) {
            ImageView imageView = imageViewList.get(i);
            int borderTop = (int) imageView.getTag(R.string.border_top);
            int borderBottom = (int) imageView.getTag(R.string.border_bottom);
            //图片的底部大于滚动的距离，即上面底部露出来了
            //图片的头部小于滚动的距离加上sv的高度，即下面的头部露出来了
            if (borderBottom > getScrollY()
                    && borderTop < getScrollY() + scrollViewHeight) {
                String imageUrl = (String) imageView.getTag(R.string.image_url);
                LoadImageTask task = new LoadImageTask(imageView);
                task.execute(imageUrl);
            } else {
                imageView.setImageResource(R.mipmap.ic_launcher);
            }
        }
    }

    /**
     * 进行一些关键性的初始化操作，获取Sv的高度，以及得到第一列的宽度值。并在这里开始加载第一列的图片
     */
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        if (changed && !loadOnce) {
            scrollViewHeight = getHeight();
            scrollLayout = getChildAt(0);
            llfirst = (LinearLayout) findViewById(R.id.ll_first);
            llSecond = (LinearLayout) findViewById(R.id.ll_second);
            llThird = (LinearLayout) findViewById(R.id.ll_third);
            columnWidth = llfirst.getWidth();
            loadOnce = true;
            loadMoreImage();
        }
    }

    private void loadMoreImage() {
        Log.e(TAG, "loadMoreImage: ");
        if (hasSDCard()) {
            int startIndex = page * PAGE_SIZE;
            int endIndex = page * PAGE_SIZE + PAGE_SIZE;
            if (startIndex < ImageUtil.imageUrls.length) {
                Toast.makeText(getContext(), "正在加载...", Toast.LENGTH_LONG).show();
                if (endIndex > ImageUtil.imageUrls.length) {
                    endIndex = ImageUtil.imageUrls.length;
                }
                //遍历当前页需要加载的图片url,去执行下载
                for (int i = startIndex; i < endIndex; i++) {
                    LoadImageTask task = new LoadImageTask(getContext());
                    taskCollection.add(task);
                    task.execute(ImageUtil.imageUrls[i]);
                }
                page++;
            } else {
                Toast.makeText(getContext(), "已没有更多图片", Toast.LENGTH_LONG).show();
            }
        }
    }

    /**
     * 监听用户到触屏时间，如果有哦那个湖手指离开屏幕，则开始进行滚动检测
     * @param v
     * @param event
     * @return
     */
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_UP) {
            Message message = Message.obtain();
            message.obj = this;
            handler.sendMessageDelayed(message, 5);
        }
        return false;
    }

    /**
     * 加载图片的任务
     */
    class LoadImageTask extends AsyncTask<String, Void, Bitmap> {
        private Context context;
        private String mImageUrl;
        //可重复使用的ImageView
        private ImageView mImageview;

        public LoadImageTask(Context context) {
            this.context = context;
        }

        /**
         * 将可重复使用的ImageView传入
         * @param imageView
         */
        public LoadImageTask(ImageView imageView) {
            mImageview = imageView;
        }

        @Override
        protected Bitmap doInBackground(String... params) {
            mImageUrl = params[0];
            Bitmap imageBitmap = ImageLoader.getBitmapFromMemoryCache(mImageUrl);
            if (imageBitmap == null) {
                imageBitmap = loadImage(mImageUrl);
            }
            return imageBitmap;
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            if (bitmap != null) {
                //算缩放比例
                double ratio  = bitmap.getWidth() / (columnWidth * 1.0);
                int scaleHeight = (int)(bitmap.getHeight() / ratio);
                addImage(bitmap, columnWidth, scaleHeight);
            }
            //加载成功，移除任务
            taskCollection.remove(this);
        }

        /**
         * 根据传入的Url，对图片进行加载。如果这张图片已经存在sk卡中，则直接从sd卡中读取，否则从网络下载
         * @param imageUrl
         * @return
         */
        private Bitmap loadImage(String imageUrl) {
            File imageFile = new File(getImagePath(imageUrl));
            if (!imageFile.exists()) {
                //如果不存在就下载,下载方法为同步方法，这里下载完，下面的从文件里取值就有了
                downloadBitmap(imageUrl);
            }
            if (imageUrl != null) {
                Bitmap bitmap = ImageLoader.loadImageFromFilePath(imageFile.getPath(), columnWidth);
                if (bitmap != null) {
                    Log.e(TAG, "加入到缓存: 内存：" + (bitmap.getByteCount() * 1.0 / 1024 / 1024) + "Mb" );
                    ImageLoader.addBitmapToMemoryCache(imageUrl, bitmap);
                    return bitmap;
                }
            }
            return null;
        }

        /**
         * 向ImageView中添加一张图片，如果有复用的ImageView，则直接显示；没有就创建一个新的ImageView，并加到ImageView列表中
         * @param bitmap
         * @param imageWidth
         * @param imageHeight
         */
        private void addImage(Bitmap bitmap, int imageWidth, int imageHeight) {
            if (mImageview != null) {
                mImageview.setImageBitmap(bitmap);
            } else {
                LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(imageWidth, imageHeight);
                ImageView imageView = new ImageView(getContext());
                imageView.setLayoutParams(params);
                imageView.setImageBitmap(bitmap);
                imageView.setScaleType(ImageView.ScaleType.FIT_XY);
                imageView.setPadding(5, 5, 5, 5);
                imageView.setTag(R.string.image_url, mImageUrl);
                findColumnToAdd(imageView, imageHeight).addView(imageView);
                imageViewList.add(imageView);
            }
        }



    }

    /**
     * 找到此时应该添加图片的一列，原则就是对三列对高度进行判断，当前高度最小对一列就是应该添加对一列
     * @param imageView
     * @param imageHeight
     * @return
     */
    private LinearLayout findColumnToAdd(ImageView imageView, int imageHeight) {
        if (firstColumnHeight <= secondColumnHeight) {
            if (firstColumnHeight <= thirdColumnHeight) {
                //第1行最矮
                imageView.setTag(R.string.border_top, firstColumnHeight);
                firstColumnHeight += imageHeight;
                imageView.setTag(R.string.border_bottom, firstColumnHeight);
                return llfirst;
            } else {
                imageView.setTag(R.string.border_top, thirdColumnHeight);
                thirdColumnHeight += imageHeight;
                imageView.setTag(R.string.border_bottom, thirdColumnHeight);
                return llThird;
            }
        } else {
            if (secondColumnHeight <= thirdColumnHeight) {
                imageView.setTag(R.string.border_top, secondColumnHeight);
                secondColumnHeight += imageHeight;
                imageView.setTag(R.string.border_bottom, secondColumnHeight);
                return llSecond;
            } else {
                imageView.setTag(R.string.border_top, thirdColumnHeight);
                thirdColumnHeight += imageHeight;
                imageView.setTag(R.string.border_bottom, thirdColumnHeight);
                return llThird;
            }
        }
    }

    /***
     * 获取图片对本地存储路径
     * @param imageUrl
     * @return
     */
    private static String getImagePath(String imageUrl) {
        int lastSlashIndex = imageUrl.lastIndexOf("/");
        String imageName = imageUrl.substring(lastSlashIndex + 1);
        String imageDir = Environment.getExternalStorageDirectory().getPath() + "/PhotoWallFalls/";
        File file = new File(imageDir);
        if (!file.exists()) {
            file.mkdirs();
        }
        return imageDir + imageName;
    }



    /**
     * 判断手机是否有SD卡
     * @return
     */
    private boolean hasSDCard() {
        return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
    }

    /**
     * 将图片下载到SD卡里缓存起来
     * @param imageUrl
     * @return
     */
    private void downloadBitmap(String imageUrl) {
        Log.e(TAG, "downloadBitmap: " + imageUrl);
        HttpURLConnection con = null;
        FileOutputStream fos = null;
        BufferedOutputStream bos = null;
        BufferedInputStream bis = null;
        File imagefile = null;
        try {
            URL url = new URL(imageUrl);
            con = (HttpURLConnection) url.openConnection();
            con.setConnectTimeout(10 * 1000);
            con.setReadTimeout(10 * 1000);
            con.setDoOutput(true);
            con.setDoInput(true);
            bis = new BufferedInputStream(con.getInputStream());
            imagefile = new File(getImagePath(imageUrl));
            fos = new FileOutputStream(imagefile);
            bos = new BufferedOutputStream(fos);
            byte[] b = new byte[1024];
            int length;
            while (((length = bis.read(b)) != -1)) {
                bos.write(b, 0 , length);
                bos.flush();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (bis != null) {
                    bis.close();
                }
                if (bos != null) {
                    bos.close();
                }
                if (con != null) {
                    con.disconnect();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        //获取图片，并保存到特定文件夹下
        /*if (imagefile != null) {
            Log.e(TAG, "downloadBitmap:  imagefile != null");
            Bitmap bitmap = ImageLoader.loadImageFromFilePath(imagefile.getPath(), columnWidth);
            if (bitmap != null) {
                Log.e(TAG, "downloadBitmap:  bitmap != null");
                imageLoader.addBitmapToMemoryCache(imageUrl, bitmap);
            }
        }*/
    }


}
